package com.spa.application.service.massagist;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.Header;
import com.spa.application.dto.login.LoginDTO;
import com.spa.application.dto.login.LoginUser;
import com.spa.application.query.member.LoginQuery;
import com.spa.domain.entity.AuthUser;
import com.spa.domain.entity.Massagist;
import com.spa.domain.service.AuthUserService;
import com.spa.domain.service.MassagistService;
import com.spa.infrastructure.enums.dict.base.RequestSourceEnum;
import com.spa.infrastructure.enums.dict.base.SourceTypeEnum;
import com.spa.infrastructure.exception.SpaException;
import com.spa.infrastructure.mapper.AuthUserMapperStruct;
import com.spa.infrastructure.repository.po.AuthUserPO;
import com.spa.infrastructure.service.sms.GenerateSmsCodeKey;
import com.spa.infrastructure.service.sms.SmsProvider;
import com.spa.infrastructure.service.wx.WXJsSdkService;
import com.spa.infrastructure.service.wx.WXLoginService;
import com.spa.infrastructure.service.wx.msg.chat.WxMpErrorMsgEnum;
import com.spa.infrastructure.service.wx.result.AccessTokenResult;
import com.spa.infrastructure.service.wx.result.ChatUserInfoResult;
import com.spa.infrastructure.util.RedisUtil;
import com.spa.infrastructure.util.ServletUtils;
import com.spa.infrastructure.util.SessionUtil;
import com.spa.infrastructure.util.StringUtils;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Slf4j
@Service
public class MassagistLoginApplicationService {

    @Resource
    private MassagistService massagistService;

    @Resource
    private GenerateSmsCodeKey smsCodeKey;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private AuthUserService authUserService;

    @Resource
    private WXLoginService wxLoginService;

    @Autowired
    private WXJsSdkService wxJsSdkService;

    @Resource
    private SmsProvider smsProvider;

    /**
     * 短信登录
     *
     * @return token
     */
    public LoginDTO smsLogin(LoginQuery login) {
        SourceTypeEnum sourceTypeEnum = SourceTypeEnum.byCode(login.getSource());
        LoginUser loginUser = new LoginUser();
        Massagist massagist = massagistService.massagistInfoByPhone(login.getPhone());
        if (BeanUtil.isEmpty(massagist)) {
            throw new SpaException("用户不存在");
        }
        loginUser.setUserId(massagist.getId());
        loginUser.setMassagist(massagist);
        //校验短信
        validateCaptchaSms(login.getPhone(), login.getSmsCode());

        String token = getLoginToken(RequestSourceEnum.Massagist, loginUser);

        String openId  = getOpenId(sourceTypeEnum, login.getCode());

        addAuthInfo(SessionUtil.getUser().getUserId(), openId, sourceTypeEnum, RequestSourceEnum.Massagist);
        return new LoginDTO(token, openId);
    }

    /**
     * 手机短信校验
     *
     * @return 结果
     */
    public void validateCaptchaSms(String phone, String smsCode) {
        String verifyKey = smsCodeKey.generateSmsCodeKey(phone, RequestSourceEnum.Massagist.getCode());
        String smsCaptcha = redisUtil.get(verifyKey);
        if (smsCaptcha == null) {
            throw new SpaException("短信验证码错误");
        }
        if (!smsCode.equalsIgnoreCase(smsCaptcha)) {
            throw new SpaException("验证码错误");
        }
    }

    /**
     * 获取登录 生成token
     *
     * @return token
     */
    public String getLoginToken(RequestSourceEnum rs, LoginUser lu) {
        try {
            StpUtil.logout(lu.getUserId());
            UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader(Header.USER_AGENT.getValue()));
            //区分手机与pc 同端互斥
            StpUtil.login(lu.getUserId(), rs.getCode());
            LoginUser loginUser = new LoginUser(lu, userAgent, rs);
            if (BeanUtil.isNotEmpty(lu.getShopUser())) {
                loginUser.setShopId(lu.getShopUser().getShopId());
            } else if (BeanUtil.isNotEmpty(lu.getMassagist())) {
                loginUser.setShopId(lu.getMassagist().getShopId());
            }
            SessionUtil.setUser(loginUser);
        } catch (Exception e) {
            Assert.isTrue(false, "生成token出错，" + e.getMessage());
        }
        // 生成token
        return StpUtil.getTokenValue();
    }

    /**
     * 添加更新授权用户
     *
     * @param userId
     * @param openId
     * @param sourceTypeEnum
     * @param requestSourceEnum
     * @return
     */
    public void addAuthInfo(Long userId, String openId, SourceTypeEnum sourceTypeEnum, RequestSourceEnum requestSourceEnum) {
        AuthUser authUser = authUserService.info(userId, sourceTypeEnum.getCode(), requestSourceEnum.getCode());
        if (BeanUtil.isNotEmpty(authUser)) {
            authUser.setUserId(userId);
            authUser.setOpenId(openId);
            authUser.setUserSource(requestSourceEnum.getCode());
            authUserService.updateInfoById(AuthUserMapperStruct.INSTANCE.entity2po(authUser));
        } else {
            //添加授权信息
            AuthUserPO po = new AuthUserPO();
            po.setOpenId(openId);
            po.setSource(sourceTypeEnum.getCode());
            po.setUserSource(requestSourceEnum.getCode());
            po.setUserId(userId);
            authUserService.addInfo(po);
        }
    }

    /**
     * 获取授权openId
     *
     * @return 结果
     */
    public String getOpenId(SourceTypeEnum sourceTypeEnum, String code) {
        String openId = "";
        if (SourceTypeEnum.WeChat.equals(sourceTypeEnum)) {
            AccessTokenResult accessTokenResult = wxLoginService.getAccessToken(code);
            openId = accessTokenResult.getOpenid();
        } else {
            throw new SpaException("请确认来源是否正确，该来源无法获取授权来源不匹配");
        }
        Assert.isTrue(StringUtils.isNotEmpty(openId), "获取授权ID失败");
        return openId;
    }

    public Integer getWxConcerned(Long userId, RequestSourceEnum requestSourceEnum) {
        log.info("getWxConcerned : {}", userId);
        AuthUser au = authUserService.info(userId, SourceTypeEnum.WeChat.getCode(), requestSourceEnum.getCode());
        log.info("AuthUser : {}", au);
        if (BeanUtil.isEmpty(au)) return 0;
        ChatUserInfoResult result = wxJsSdkService.getUserInfo(SourceTypeEnum.WeChat, au.getOpenId());
        if (ObjectUtil.isNotNull(result.getErrcode()) && result.getErrcode() != 0) {
            log.error("查询是否关注公众号 error msg={}", WxMpErrorMsgEnum.findMsgByCode(result.getErrcode()));
            throw new SpaException("查询是否关注公众号失败");
        }
        return result.getSubscribe();
    }

    public void sendSms(String phone) {
        Massagist massagist = massagistService.massagistInfoByPhone(phone);
        if (BeanUtil.isEmpty(massagist)) {
            throw new SpaException("用户不存在");
        }
        String key = smsCodeKey.generateSmsCodeKey(phone, RequestSourceEnum.Massagist.getCode());
        smsProvider.sendVerificationCode(phone, key);
    }
}
